package org.chl.sqlsession.sqltemplate.core;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 模板执行器工厂
 */
@ConfigurationProperties(prefix = "sql.template")
public class SqlTemplateFactory {

	private static Logger logger = LoggerFactory.getLogger(SqlTemplateFactory.class);

	private ConcurrentHashMap<String, SqlTemplate> templateCache;

	private String locations = "classpath*:*.xml";

	public SqlTemplateFactory() {
		templateCache = new ConcurrentHashMap<String, SqlTemplate>();
	}

	@PostConstruct
	public void init() throws IOException {
		ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
		Resource[] mappers = resourceResolver.getResources(locations);
		for (Resource resource: mappers) {
			InputStream inputStream = null;
			try {
				inputStream = resource.getInputStream();
				Set<String> templateId = createTemplate(inputStream);
				logger.info("load the {} sql id in:{}", resource.getURI(), templateId);
			} catch (Exception e) {
				logger.warn("error constructing the {}", resource.getURI(), e);
			} finally {
				if (Objects.nonNull(inputStream)) {
					inputStream.close();
				}
			}
		}
	}

	public SqlTemplate getTemplate(final String sqlId) {
		SqlTemplate sqlTemplate = templateCache.get(sqlId);
		if (Objects.isNull(sqlTemplate)) {
			throw new RuntimeException(String.format("not exist sql id: %s", sqlId));
		}
		return sqlTemplate;
	}

	private Set<String> createTemplate(InputStream scriptFile) {
		Map<String, SqlTemplate> sqlTemplateMap = new SqlTemplate.SqlTemplateBuilder(scriptFile).build();
		templateCache.putAll(sqlTemplateMap);
		return sqlTemplateMap.keySet();
	}

	public String getLocations() {
		return locations;
	}

	public void setLocations(String locations) {
		this.locations = locations;
	}
}
